test discovery 2.0#25760
Conversation
- Created ProjectAdapter and WorkspaceDiscoveryState interfaces - Added project utility functions (ID generation, scoping, nested project detection) - Updated PythonResultResolver to support optional projectId parameter - Modified populateTestTree to create project-scoped test IDs - Updated TestDiscoveryHandler to handle project-scoped error nodes Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
- Added project-based state maps (workspaceProjects, vsIdToProject, fileUriToProject, projectToVsIds) - Implemented discoverWorkspaceProjects() to query Python Environment API - Created createProjectAdapter() to build ProjectAdapter from PythonProject - Added createDefaultProject() for backward compatibility - Imported necessary types from environment API - Added flag to enable/disable project-based testing Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
- Modified activate() to check useProjectBasedTesting flag - Calls discoverWorkspaceProjects() for each workspace when enabled - Populates workspaceProjects map with discovered projects - Created activateLegacyWorkspace() for backward compatibility - Falls back to legacy mode if project discovery fails - Maintains full backward compatibility with flag disabled Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR implements project-based test discovery for pytest, enabling multi-project workspace support where each Python project gets its own test tree root with its own Python environment. When the Python Environments API is available, the extension now discovers Python projects within workspaces and creates separate test adapters for each project.
Changes:
- Introduces TestProjectRegistry for managing project lifecycle, discovery, and nested project handling
- Adds ProjectAdapter interface representing individual Python projects with test infrastructure
- Implements Python-side
get_test_root_path()function to support project-scoped test trees - Adds comprehensive unit tests for project registry, utilities, and Python-side functions
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/client/testing/testController/controller.ts | Refactored activation to support project-based and legacy modes, added project discovery orchestration |
| src/client/testing/testController/common/testProjectRegistry.ts | New registry class managing Python project discovery, adapter creation, and nested project ignore lists |
| src/client/testing/testController/common/projectAdapter.ts | New interface defining structure for project-based test infrastructure |
| src/client/testing/testController/common/projectUtils.ts | Utility functions for project ID generation, display names, and adapter creation |
| src/client/testing/testController/common/resultResolver.ts | Added optional projectId parameter for scoping test IDs to projects |
| src/client/testing/testController/common/utils.ts | Modified populateTestTree to support project-scoped test IDs with separator |
| src/client/testing/testController/common/types.ts | Extracted ITestItemMappings interface, added optional project parameter to ITestDiscoveryAdapter |
| src/client/testing/testController/common/testDiscoveryHandler.ts | Updated error node creation to support project-scoped IDs |
| src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts | Added PROJECT_ROOT_PATH env var and --ignore flags for nested projects |
| python_files/vscode_pytest/init.py | Implemented get_test_root_path() function to return project root or cwd for test tree structure |
| src/test/testing/testController/controller.unit.test.ts | Added tests for controller project-based testing functionality |
| src/test/testing/testController/common/testProjectRegistry.unit.test.ts | Comprehensive tests for TestProjectRegistry class |
| src/test/testing/testController/common/projectUtils.unit.test.ts | Tests for project utility functions (getProjectId, parseVsId, createProjectDisplayName) |
| python_files/tests/pytestadapter/test_discovery.py | Added test_project_root_path_env_var() to verify PROJECT_ROOT_PATH behavior |
| python_files/tests/pytestadapter/expected_discovery_test_output.py | Added expected output for PROJECT_ROOT_PATH test scenario |
| .github/instructions/testing_feature_area.instructions.md | Documented project-based testing architecture and workflow |
| .github/instructions/testing-workflow.instructions.md | Added learning about stubbing after refactoring |
src/client/testing/testController/common/testProjectRegistry.ts
Outdated
Show resolved
Hide resolved
| # ===================================================================================== | ||
| # PROJECT_ROOT_PATH environment variable tests | ||
| # These test the project-based testing feature where PROJECT_ROOT_PATH changes | ||
| # the test tree root from cwd to the specified project path. |
There was a problem hiding this comment.
in the diagram- outline where the projects are configured in this setup
| raise VSCodePytestError( | ||
| f"Error occurred while calculating symlink equivalent from node path: {e}" | ||
| f"\n SYMLINK_PATH: {SYMLINK_PATH}, \n node path: {node_path}, \n cwd: {_CACHED_CWD if _CACHED_CWD else pathlib.Path.cwd()}" | ||
| f"\n SYMLINK_PATH: {SYMLINK_PATH}, \n node path: {node_path}, \n cwd: {_CACHED_CWD or pathlib.Path.cwd()}" |
There was a problem hiding this comment.
can we add a test which verifies symlinks work with the project based setup? Look at old symlink tests for reference
|
|
||
| /** | ||
| * Creates test adapters (discovery and execution) for a given test provider. | ||
| * Centralizes adapter creation to avoid code duplication across Controller and TestProjectRegistry. |
There was a problem hiding this comment.
remove line: Centralizes adapter creation to avoid code duplication across Controller and TestProjectRegistry.
|
|
||
| constructor(testController: TestController, testProvider: TestProvider, private workspaceUri: Uri) { | ||
| /** | ||
| * Optional project ID for scoping test IDs. |
There was a problem hiding this comment.
in another file the export const PROJECT_ID_SEPARATOR = '@@vsc@@'; should these not be the same?
| export class TestProjectRegistry { | ||
| /** | ||
| * Map of workspace URI -> Map of project ID -> ProjectAdapter | ||
| * Project IDs match Python Environments extension's Map<string, PythonProject> keys |
There was a problem hiding this comment.
this is confusing- clarify this concept better
| throw new Error(`No Python environment found for project ${projectId}`); | ||
| } | ||
|
|
||
| // Create test infrastructure |
There was a problem hiding this comment.
clarify test infra per project
| /** | ||
| * Identifies nested projects and returns ignore paths for parent projects. | ||
| */ | ||
| private computeNestedProjectIgnores(workspaceUri: Uri): Map<string, string[]> { |
There was a problem hiding this comment.
add time complexity to doc string
| * When true, discovers and manages tests per-project using Python Environments API. | ||
| * When false, uses legacy single-workspace mode. | ||
| */ | ||
| private readonly useProjectBasedTesting = true; |
There was a problem hiding this comment.
remove this feature flag- instead it will operate based on the useEnvExtension variable
| project.projectUri, | ||
| this.pythonExecFactory, | ||
| this.refreshCancellation.token, | ||
| undefined, // Interpreter not needed; adapter uses Python Environments API |
There was a problem hiding this comment.
update the discover test definition to specify this is how it will work (for clarity)
| // NOTE: | ||
| // `PythonTestController` calls `vscode.tests.createTestController(...)` in its constructor. | ||
| // In unit tests, `vscode` is a mocked module (see `src/test/vscode-mock.ts`) and it does not |
There was a problem hiding this comment.
it seems easier to maybe just add test namespace to the vscode mock module right?
## Summary This PR implements **project-based test discovery** for pytest, enabling multi-project workspace support. When the Python Environments API is available, the extension now discovers Python projects within workspaces and creates separate test tree roots for each project with its own Python environment. ## What's New ### Project-Based Testing Architecture - **TestProjectRegistry**: Manages the lifecycle of Python test projects, including: - Discovering projects via Python Environments API - Creating ProjectAdapter instances per workspace - Computing nested project relationships for ignore lists - Fallback to "legacy" single-adapter mode when API unavailable - **ProjectAdapter**: Interface representing a single Python project with test infrastructure: - Project identity (ID, name, URI) - Python environment from the environments API - Test framework adapters (discovery/execution) - Nested project ignore paths ### Key Features - ✅ **Multi-project workspaces**: Each Python project gets its own test tree root - ✅ **Nested project handling**: Parent projects automatically ignore nested child projects via `--ignore` flags - ✅ **Graceful fallback**: Falls back to legacy single-adapter mode if Python Environments API is unavailable - ✅ **Project root path**: Python-side `get_test_root_path()` function returns appropriate root for test tree ### Code Improvements - Standardized logging prefixes to `[test-by-project]` across all files - Centralized adapter creation via `createTestAdapters()` helper method - Extracted reusable methods for discovery, execution, and file watching ## Scope & Limitations > **⚠️ Important: unittest is NOT supported in this PR** > > This PR focuses exclusively on **pytest**. unittest support for project-based testing will be implemented in a future PR. ## Testing - Added unit tests for `TestProjectRegistry` class - Added unit tests for Python-side `get_test_root_path()` function - Manual testing with multi-project workspaces ## Related Issues first step in: microsoft/vscode-python-environments#987 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Summary
This PR implements project-based test discovery for pytest, enabling multi-project workspace support. When the Python Environments API is available, the extension now discovers Python projects within workspaces and creates separate test tree roots for each project with its own Python environment.
What's New
Project-Based Testing Architecture
TestProjectRegistry: Manages the lifecycle of Python test projects, including:
ProjectAdapter: Interface representing a single Python project with test infrastructure:
Key Features
--ignoreflagsget_test_root_path()function returns appropriate root for test treeCode Improvements
[test-by-project]across all filescreateTestAdapters()helper methodScope & Limitations
Testing
TestProjectRegistryclassget_test_root_path()functionRelated Issues
first step in: microsoft/vscode-python-environments#987